//////////////////////////////////////////////
// Matrix.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkMaths
{
	class Quaternion ;
	class Vector ;
}

/// Includes ---------------------------------

// nkGraphics
#include "../Dll/DllDefines.h"

// nkCommon
#include <nilkinsCommon/Patterns/ByteAlignedClass.h>

// nkMemory
#include <NilkinsMemory/Containers/StringView.h>

/// Class ------------------------------------

namespace nkMaths
{
	class DLL_MATHS_EXPORT Matrix
	{		
		public :
		
			// Constructor, destructor
			Matrix () noexcept ;
			Matrix (float m00, float m01, float m10, float m11) noexcept ;
			Matrix (float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) noexcept ;
			Matrix (float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33) noexcept ;
			Matrix (const Matrix& other) noexcept ;

			// Getters
			Vector getRow0 () const ;
			Vector getRow1 () const ;
			Vector getRow2 () const ;
			Vector getRow3 () const ;
			Vector getCol0 () const ;
			Vector getCol1 () const ;
			Vector getCol2 () const ;
			Vector getCol3 () const ;
			float get (unsigned int row, unsigned int col) const ;

			// Setters
			Matrix& set (float val, unsigned int row, unsigned int col) ;

			// Alterations
			Matrix getInverseMat2 () const ;
			Matrix getInverseMat3 () const ;
			Matrix getInverseMat4 () const ;
			Matrix getTranspose () const ;
			Matrix& inverseMat2 () ;
			Matrix& inverseMat3 () ;
			Matrix& inverseMat4 () ;
			Matrix& transpose () ;

			// Transformations
			Vector getPositionComponent () const ;
			Matrix getOrientationComponent () const ;
			Vector getScaleComponent () const ;
			void getDecomposed (Vector& position, Matrix& orientation, Vector& scale) const ;

			Matrix& setToViewMatrixDirection (const Vector& position, const Vector& direction, const Vector& upDirection) ;
			Matrix& setToPerspectiveMatrix (float fov, float aspect, float near, float far) ;
			Matrix& setToPerspectiveReverseZMatrix (float fov, float aspect, float near, float far = -1.f) ;
			Matrix& setToOffCenterPerspectiveMatrix (float fovLeft, float fovRight, float fovTop, float fovBottom, float near, float far) ;
			Matrix& setToOffCenterPerspectiveReverseZMatrix (float fovLeft, float fovRight, float fovTop, float fovBottom, float near, float far = -1.f) ;
			Matrix& setToOrthographicMatrix (float widthNearPlane, float heightNearPlane, float near, float far) ;
			Matrix& setToOrthographicReverseZMatrix (float widthNearPlane, float heightNearPlane, float near, float far) ;
			Matrix& setPositionComponent (const Vector& position) ;
			Matrix& setOrientationComponent (const Quaternion& rot) ;
			Matrix& setScaleComponent (const Vector& scale) ;
			Matrix& setToTransformation (const Vector& position, const Quaternion& orientation, const Vector& scale) ;
			
			// Utilities
			float getDeterminantMat2 () const ;
			float getDeterminantMat3 () const ;
			float getDeterminantMat4 () const ;
			float getTraceMat2 () const ;
			float getTraceMat3 () const ;
			float getTraceMat4 () const ;

			// Pratique
			nkMemory::String toString () const ;
			Matrix& fromString (nkMemory::StringView str) ;

			// Les opérations
			// Assignation
			Matrix& operator= (const Matrix& other) noexcept ;
			// Egalité
			bool operator== (const Matrix& other) ;
			bool operator!= (const Matrix& other) ;
			// Addition
			Matrix operator+ (const Matrix& other) const ;
			void operator+= (const Matrix& other) ;
			// Soustraction
			Matrix operator- (const Matrix& other) const ;
			void operator-= (const Matrix& other) ;
			// Multiplications et transfo
			Matrix operator* (const Matrix& other) const ;
			Vector operator* (const Vector& vec) const ;
			Quaternion operator* (const Quaternion& q) const ;
			Matrix operator* (float scalar) const ;
			void operator*= (const Matrix& other) ;
			void operator*= (float scalar) ;
			// Division
			Matrix operator/ (float scalar) const ;
			void operator/= (float scalar) ;

		public :
	
			// Attributes
			float _m [4][4] ;
	} ;
}